﻿using APP.IO;
using APP.OpenCV;
using MinesweeperAutoScanDemo.Model;
using NotifyPropertyBase;
using ScreenCapture;
using ScreenCapture.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Library.Json;
using System.Threading;

namespace MinesweeperAutoScanDemo.ViewModel
{
    internal class MainViewModel : ViewModelBase
    {

        public event Action<bool> WindowVisibleEventHandel;

        public MainViewModel()
        {
            CaptureWindowImageCommand = new RelayCommand(CaptureWindowImageMethod);
            ReCaptureWindowImageCommand = new RelayCommand(ReCaptureWindowImageMethod);
            MarkNumberCommand = new RelayCommand<EarthModel>(MarkNumberMethod);
            MarkStatusCommand = new RelayCommand<EarthModel>(MarkStatusMethod);
            ClickEarthItemCommand = new RelayCommand<EarthModel>(ClickEarthItemMethod);
            AutoScanBomboCommand = new RelayCommand(AutoScanBomboMethod);
            ClearEarthCommand = new RelayCommand(ClearEarthMethod);
            CreateTemplateCommand = new RelayCommand(CreateTemplateMethod);
            MaxRow = Rows;
            MaxColumn = Columns;
            Init();
            InitMatchModel();
        }

        ~MainViewModel()
        {
            if (!Debug)
            {
                var folder = PathHelper.GetPath(FolderType.Temp, "ImageTest");
                var folder2 = PathHelper.GetPath(FolderType.Temp, "Image");

                try
                {
                    Directory.Delete(folder, true);
                    Directory.Delete(folder2, true);
                }
                catch (Exception ex)
                {

                }
            }

        }
        //识别步骤
        //1.首先选窗体自由截图 这样每次 都能定位方块切图 
        //2.尽可能打开界面或者找各种数字模型的模版，将这些图片做出模版
        //3.没有识别的图片，根据其特性我这边是做了均值方差，mean 发现 临界点在80左右，所以80一下识别数字没事识别出来就当是空白0，80上识别已标记的炸弹，没事别出来就当做是没点击的空地
        //4.另有右键辅助更改，识别出错的时候有机会更改，
        //5.自动扫雷目前 里面加了循环按道理要搞个单次的，这次不加了，有兴趣的搞一下
        //6.目前自动扫雷的逻辑是
        //1. 九宫格内  数字等于未开发时  未开发全部标记成雷
        //2. 九宫格内  数字等于已标记雷数，双击打开未开发地区
        //3. 没有未开发区域的忽略
        //4. 所以当有复杂逻辑时还是需要手动解答，谁有兴趣自己研究一下，这个程序主要是提出一种思想和解决问题的思路。

        //待解决问题 
        //1.主界面不更新了
        //2.不用过滤 已经点过的点，如果存在没开放的地块仍然可以双击
        //3.如果没有匹配出数字 ，大于80 可以认为是蓝色 

        /// <summary>
        /// Debug  开启会输出部分图片
        /// </summary>
        public bool Debug { get; set; } = true;

        public void Init()
        {
            var folder = PathHelper.GetPath(FolderType.Temp, "Data");
            var windowINfoPath = Path.Combine(folder, "windowinfo.json");
            var earthInfoPath = Path.Combine(folder, "earth.json");

            if (File.Exists(windowINfoPath))
            {
                var windoInfoString = File.ReadAllText(windowINfoPath);
                if (!string.IsNullOrEmpty(windoInfoString))
                {
                    WindowInfo = windoInfoString.FromJson<WindowInfo>();

                }
            }
            try
            {
                if (File.Exists(earthInfoPath))
                {
                    var earthInfoString = File.ReadAllText(earthInfoPath);
                    if (!string.IsNullOrEmpty(earthInfoString))
                    {
                        var listEarthModel = earthInfoString.FromJson<List<EarthModel>>();

                        var notExistList = listEarthModel.Where(x => !File.Exists(x.ImagePath)).ToList();
                        listEarthModel = listEarthModel.Except(notExistList).ToList();
                        //listEarthModel.ForEach(model =>
                        //{
                        //    if (!File.Exists(model.ImagePath))
                        //    {
                        //        model.ImagePath = null;
                        //    }
                        //});
                        EathItemsSource = new ObservableCollection<EarthModel>(listEarthModel);
                    }
                }
            }
            catch (Exception ex)
            {

            }
            //ReCaptureWindowImageMethod();
        }

        public void InitMatchModel()
        {
            ImageMatchInstance = new ImageMatchModel();

            //var sourceFolder = @"C:\Users\Administrator\Documents\MyAPP\Temp\OrigineTemplate\";
            var sourceFolder = Environment.CurrentDirectory + @"\Resource\OrigineTemplate\";
            ImageMatchInstance.InitSource(sourceFolder);

            //tempTest
            //var strFolder = @"C:\Users\Administrator\Documents\MyAPP\Temp\ImageTest\testDff\";
            //var files = new DirectoryInfo(strFolder).GetFiles();
            //List<object> list = new List<object>();
            //foreach (var file in files)
            //{
            //    var data = ImageMatchInstance.MatchTemplate(file.FullName);
            //    if (data != null)
            //    {

            //    }
            //}
        }
        private void CreateTemplateMethod()
        {
            ImageMatchInstance = new ImageMatchModel();
            var folder = PathHelper.GetPath(FolderType.Temp, "ImageNotRecognize");
            //var sourceFolder = @"C:\Users\Administrator\Documents\MyAPP\Temp\ImageNotRecognize\";
            var tempLateFolder = Environment.CurrentDirectory + @"\Resource\OrigineTemplate\";
            //var tempLateFolder = @"C:\Users\Administrator\Documents\MyAPP\Temp\OrigineTemplate\";
            ImageMatchInstance.CreateTemplate(folder, tempLateFolder);

        }


        public void Save()
        {
            var folder = PathHelper.GetPath(FolderType.Temp, "Data");
            var windowINfoPath = Path.Combine(folder, "windowinfo.json");
            var earthInfoPath = Path.Combine(folder, "earth.json");

            File.WriteAllText(windowINfoPath, WindowInfo.ToJson());
            File.WriteAllText(earthInfoPath, EathItemsSource.ToList().ToJson());

        }


        private int _Rows = 24;
        public int Rows { get => _Rows; set => Set(ref _Rows, value); }

        private int _Columns = 30;
        public int Columns { get => _Columns; set => Set(ref _Columns, value); }

        public static int MaxRow;
        public static int MaxColumn;

        private ObservableCollection<EarthModel> _EathItemsSource;
        public ObservableCollection<EarthModel> EathItemsSource { get => _EathItemsSource; set => Set(ref _EathItemsSource, value); }


        private ObservableCollection<EarthModel> _MarkedEathItemsSource;
        public ObservableCollection<EarthModel> MarkedEathItemsSource { get => _MarkedEathItemsSource; set => Set(ref _MarkedEathItemsSource, value); }


        public RelayCommand CreateTemplateCommand { get; set; }
        public RelayCommand CaptureWindowImageCommand { get; set; }
        public RelayCommand ClearEarthCommand { get; set; }
        public RelayCommand ReCaptureWindowImageCommand { get; set; }
        public RelayCommand<EarthModel> MarkNumberCommand { get; set; }
        public RelayCommand<EarthModel> MarkStatusCommand { get; set; }
        public RelayCommand<EarthModel> ClickEarthItemCommand { get; set; }

        public RelayCommand AutoScanBomboCommand { get; set; }

        public static System.Drawing.Rectangle WindowsInnerRectForFullScreen { get; set; }

        List<EarthModel> MatchedList = new List<EarthModel>();

        ImageMatchModel ImageMatchInstance { get; set; }

        public WindowInfo WindowInfo { get; set; }


        private void CaptureWindowImageMethod()
        {
            this.WindowVisibleEventHandel?.Invoke(false);
            var screenCapture = new ScreenCaptureHelper();
            var windowInfo = screenCapture.ScreenCapture_SelectWindow();
            if (windowInfo == null)
            {
                return;
            }
            WindowInfo = windowInfo;
            var backImage = screenCapture.WindowCapture(windowInfo);
            if (backImage == null)
            {
                return;
            }
            WindowsInnerRectForFullScreen = windowInfo.WindowsInnerRectForFullScreen;
            this.WindowVisibleEventHandel?.Invoke(true);
            if (backImage != null)
            {
                //var imageFolder = PathHelper.GetPath(FolderType.Temp, "Image");
                //var imageFile = PathHelper.GetTempFileName(imageFolder, ".png");
                //backImage.Save(imageFile, System.Drawing.Imaging.ImageFormat.Png);

                var imageChips = OCRHelper.SplitImage(backImage, Columns, Rows);
                var list = imageChips.Select(x => new EarthModel(x)).ToList();
                UpdateMatch(list);
            }
        }

        private void ReCaptureWindowImageMethod()
        {
            if (WindowInfo != null)
            {
                MatchedList = EathItemsSource.Where(x => x.Status != Enums.EathStatus.Earth).ToList();
                this.WindowVisibleEventHandel?.Invoke(false);
                if (WindowInfo.FullScreenImageBitmap != null)
                {
                    WindowInfo.FullScreenImageBitmap.Dispose();
                }
                var innerImageBack = WindowInfo.ReCaptureAndSaveWindowInnerRectImage();
                WindowInfo.ReLocateWindowInnerRect();
                WindowsInnerRectForFullScreen = WindowInfo.WindowsInnerRectForFullScreen;
                this.WindowVisibleEventHandel?.Invoke(true);
                EathItemsSource.ToList().ForEach(x =>
                {
                    if (x.ImageChip?.Image != null)
                    {
                        x.ImageChip.Image.Dispose();
                    }
                });
                var backImage = new System.Drawing.Bitmap(innerImageBack.Data);
                var imageChips = OCRHelper.SplitImage(backImage, Columns, Rows);
                var list = imageChips.Select(x => new EarthModel(x)).ToList();
                //System.Windows.Application.Current.Dispatcher.Invoke(() =>
                //{
                UpdateMatch(list);
                //});
            }
        }
        public void UpdateMatch(List<EarthModel> list)
        {
            var recognizedList = list.Where(x => x.Status == Enums.EathStatus.Earth).ToList();
            //var waitOCRList = list.Where(x => !MatchedList.Any(y => y.Row == x.Row && y.Column == x.Column)).ToList();
            var waitOCRList = recognizedList;
            foreach (var item in waitOCRList)
            {
                var ocrBack = ImageMatchInstance.MatchTemplate(item.ImagePath, out double meanH);
                if (ocrBack != null)
                {
                    if (ocrBack.TemplateType == TemplateType.Number)
                    {
                        item.Status = Enums.EathStatus.Open;
                        item.BomboNumber = ocrBack.Number;
                        MatchedList.Add(item);
                    }
                    else if (ocrBack.TemplateType == TemplateType.Bombo)
                    {
                        item.Status = Enums.EathStatus.MarkBombo;
                        //item.BomboNumber = ocrBack.Number;
                        MatchedList.Add(item);
                    }
                    else if (ocrBack.TemplateType == TemplateType.Empty)
                    {
                        item.Status = Enums.EathStatus.Open;
                        item.BomboNumber = 0;
                        MatchedList.Add(item);
                    }
                    else
                    {
                        if (Debug)
                        {
                            var notRecoFolder = PathHelper.GetPath(FolderType.Temp, "ImageNotRecognize");
                            PathHelper.MoveFileFolder(item.ImagePath, notRecoFolder, true);
                        }
                    }
                }
                else
                {
                    if (meanH > 80)
                    {
                        continue;
                    }
                    if (Debug)
                    {
                        var notRecoFolder = PathHelper.GetPath(FolderType.Temp, "ImageNotRecognize");
                        PathHelper.MoveFileFolder(item.ImagePath, notRecoFolder, true);
                    }
                }
            }

            MatchedList.ForEach(x =>
            {
                var item = list.FirstOrDefault(y => y.Row == x.Row && y.Column == x.Column);
                if (item != null)
                {
                    item.Status = x.Status;
                    item.BomboNumber = x.BomboNumber;
                }
            });
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                EathItemsSource = new ObservableCollection<EarthModel>(list);
                Save();
            });
        }
        private void ClearEarthMethod()
        {
            MatchedList.Clear();
            scanBomboPeoples.Clear();
            EathItemsSource = new ObservableCollection<EarthModel>();
            Save();
        }


        private void MarkStatusMethod(EarthModel obj)
        {

        }

        private void MarkNumberMethod(EarthModel obj)
        {

        }
        private void ClickEarthItemMethod(EarthModel obj)
        {
            //var x = WindowsInnerRectForFullScreen.X + obj.Column * obj.ImageChip.Image.Width + obj.ImageChip.Image.Width / 2;
            //var y = WindowsInnerRectForFullScreen.Y + obj.Row * obj.ImageChip.Image.Height + obj.ImageChip.Image.Height / 2;

            //AutoIt.AutoItX.MouseMove(x, y);
            //AutoIt.AutoItX.MouseClick("LEFT", x, y, 3);
            if (obj.Status == Enums.EathStatus.Earth)
            {
                obj.Status = Enums.EathStatus.Open;
                obj.BomboNumber = 0;
            }
            else
            {
                obj.Status = Enums.EathStatus.Open;
                obj.BomboNumber++;
                if (obj.BomboNumber > 9)
                {
                    obj.BomboNumber = 0;
                    obj.Status = Enums.EathStatus.Earth;
                }
            }
        }


        private void AutoScanBomboMethod()
        {
            var back = WindowInfo.ReCaptureWindow();
            if (back.Success)
            {
                WindowInfo.ReLocateWindowInnerRect();
            }
            var x = WindowInfo.WindowRect.Right - 10;
            var y = WindowInfo.WindowRect.Bottom - 10;

            AutoIt.AutoItX.MouseMove(x, y);
            AutoIt.AutoItX.MouseClick("LEFT", x, y, 1);

            Task.Run(() =>
            {
                while (true)
                {
                    scanBomboPeoples.Clear();
                    foreach (var item in EathItemsSource)
                    {
                        var itemList = Get9EarthBoard(item);
                        var tempModel = new ScanBomboPeople(item, itemList);
                        scanBomboPeoples.Add(tempModel);
                    }

                    if (!scanBomboPeoples.Any(item => item.HasActEarth() == true))
                    {
                        break;
                    }

                    scanBomboPeoples.ForEach(item => item.MarkBomboClick());
                    scanBomboPeoples.ForEach(item => item.DoubleClickOpen());
                    Save();
                    ReCaptureWindowImageMethod();
                    Thread.Sleep(300);
                }

                //HasActList = HasActList
                //ReCaptureWindowImageMethod();
                Save();
            });
        }
        List<ScanBomboPeople> scanBomboPeoples = new List<ScanBomboPeople>();
        static List<EarthModel> HasActList = new List<EarthModel>();

        public List<EarthModel> Get9EarthBoard(EarthModel earthModel)
        {
            List<EarthModel> earthModels = new List<EarthModel>();

            for (int column = earthModel.Column - 1; column <= earthModel.Column + 1; column++)
            {
                if (column < 0)
                {
                    continue;
                }
                if (column > Columns - 1)
                {
                    continue;
                }
                for (int row = earthModel.Row - 1; row <= earthModel.Row + 1; row++)
                {
                    if (row < 0)
                    {
                        continue;
                    }
                    if (row > Rows - 1)
                    {
                        continue;
                    }

                    if (row == earthModel.Row && column == earthModel.Column)
                    {
                        continue;
                    }

                    var earthItem = EathItemsSource.FirstOrDefault(x => x.Column == column && x.Row == row);
                    if (earthItem != null)
                    {
                        earthModels.Add(earthItem);
                    }
                    else
                    {

                    }
                }
            }
            return earthModels;
        }

        public class ScanBomboPeople
        {

            public ScanBomboPeople(EarthModel earthModel, List<EarthModel> earthModels)
            {
                CenterEarth = earthModel;
                Earth9List = earthModels;
            }
            public EarthModel CenterEarth { get; set; }
            public List<EarthModel> Earth9List { get; set; }

            public void AutoScan()
            {
                DoubleClickOpen();
            }


            public bool IsWaitCheck()
            {
                //如果是空白或者已经标记为炸弹则没必要管
                if (CenterEarth.Status == Enums.EathStatus.Earth || CenterEarth.Status == Enums.EathStatus.MarkBombo)
                {
                    return false;
                }
                return (Earth9List.Count(x => x.Status == Enums.EathStatus.Earth) > 0);
            }

            public bool HasMarkBombo9()
            {
                bool hasAct = false;
                if (!IsWaitCheck())
                {
                    return hasAct;
                }
                if (CenterEarth.BomboNumber ==
                  Earth9List.Count(x => x.Status == Enums.EathStatus.MarkBombo || x.Status == Enums.EathStatus.Earth))
                {
                    return true;
                }
                return hasAct;
            }

            public bool HasDoubleClick9()
            {
                if (!IsWaitCheck())
                {
                    return false;
                }
                if (CenterEarth.BomboNumber ==
                  Earth9List.Count(x => x.Status == Enums.EathStatus.MarkBombo))
                {
                    return true;
                }
                return false;
            }

            public bool HasActEarth()
            {
                return HasMarkBombo9() || HasDoubleClick9();
            }

            public void MarkBomboClick()
            {
                if (!IsWaitCheck())
                {
                    return;
                }
                if (CenterEarth.BomboNumber ==
                  Earth9List.Count(x => x.Status == Enums.EathStatus.MarkBombo || x.Status == Enums.EathStatus.Earth))
                {
                    var earthItemList = Earth9List.Where(x => x.Status == Enums.EathStatus.Earth).ToList();
                    foreach (var earthItem in earthItemList)
                    {
                        //if (HasActList.Contains(earthItem))
                        //{
                        //    return;
                        //}
                        earthItem.MarkBomboClick(WindowsInnerRectForFullScreen);
                        earthItem.Status = Enums.EathStatus.MarkBombo;
                        HasActList.Add(earthItem);
                    }
                }
            }
            public void DoubleClickOpen()
            {
                if (!IsWaitCheck())
                {
                    return;
                }
                if (CenterEarth.BomboNumber > 0
                    && CenterEarth.BomboNumber == Earth9List.Count(x => x.Status == Enums.EathStatus.MarkBombo)
                    && Earth9List.Count(x => x.Status == Enums.EathStatus.Earth) >= 1
                    )
                {
                    //if (HasActList.Contains(CenterEarth))
                    //{
                    //    return;
                    //}
                    //var earthItem = Earth9List.First(x => x.Status != Enums.EathStatus.Open);
                    CenterEarth.DoubleClick(WindowsInnerRectForFullScreen);
                    HasActList.Add(CenterEarth);
                }
            }
        }
    }
}
